package top.happyone.security.demo.conf;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import top.happyone.security.demo.pojo.Admin;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * /oauth/authorize：授权端点。
 * /oauth/token：令牌端点。
 * /oauth/confirm_access：用户确认授权提交端点。
 * /oauth/error：授权服务错误信息端点。
 * /oauth/check_token：用于资源服务访问的令牌解析端点。
 * /oauth/token_key：提供公有密匙的端点，如果你使用JWT令牌的话。
 * <p>
 * 用户使用相关（非管理员）
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Value("my.security.signKey")
    private String signKey;

    @Autowired
    private DataSource dataSource;

    /**
     * 开启 /oauth/token_key验证端口,可匿名访问
     * 开启 /oauth/check_token断点，有权限访问
     * <p>
     * 允许所有人认证token
     * security.tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()");
     * </p>
     * 用于资源服务器验证授权服务器发放的token真伪性
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        super.configure(security);
        /*security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients();*/
    }

    /**
     * 配置jwt相关配置
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //增强token
        List<TokenEnhancer> enhancerList = Arrays.asList(JwtAccessTokenConverter(), jwtTokenEnhancer());
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        enhancerChain.setTokenEnhancers(enhancerList);
        endpoints
                .tokenStore(jwtTokenStore())
                .tokenEnhancer(enhancerChain);


    }

    /**
     * 配置可信任的第三方应用
     * 其中 happyone-trust 是可以进行token认证
     * happyone 不行
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 内存
        /*clients.inMemory()
                .withClient("happyone")
                .secret(passwordEncoder().encode("happyone-secret"))
                .redirectUris("http://localhost:8090")
                .authorizedGrantTypes("authorization_code")
                .scopes("all")
                .and()
                .withClient("happyone-trust")
                .secret(passwordEncoder().encode("happyone-secret"))
                .redirectUris("http://localhost:8090")
                .authorizedGrantTypes("authorization_code")
                .authorities("ROLE_TRUSTED_CLIENT")
                .scopes("all");*/
        // 数据库验证
        clients.withClientDetails(clientDetails());
    }

    @Bean
    public JdbcClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }


    /**
     * 配置token--》JwtToken
     */
    @Bean
    public JwtAccessTokenConverter JwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter();
        jwtConverter.setSigningKey(signKey);
        return jwtConverter;
    }

    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(JwtAccessTokenConverter());
    }

    /**
     * 增强字段
     *
     * @return
     */
    @Bean
    public TokenEnhancer jwtTokenEnhancer() {
        return new TokenEnhancer() {
            @Override
            public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
                //设置id
                User user = (User) authentication.getUserAuthentication().getPrincipal();
                Map additionalInformation = accessToken.getAdditionalInformation();
                additionalInformation.put("id", user.getUsername());
                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
                return accessToken;
            }
        };
    }

    /**
     * 内存模式:5版本后，clientSecret需要加密。
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
